跳至主要内容

Removing Digits

題目

給定一正整數 nn,且每次操作都能將一個一個數字減去他自己的其中一個位數的數字,求最少需要幾次操作能讓該數字變成 00 ?

輸入

輸入一個正整數 nn。(1n1061 \le n \le 10^6

輸出

輸出最少需要經過幾次操作使 nn 變成 00

範例測資

Input:
27

Output:
5
  • 277=2027 - 7 = 20
  • 202=1820 - 2 = 18
  • 188=1018 - 8 = 10
  • 101=910 - 1 = 9
  • 99=09 - 9 = 0

總共經過 55 次操作

想法 1 : 貪心

相信看完範例測資後大部分的人都會直覺想到貪心解法,也就是每次都減掉所有位數裡面最大的那一個即可。

證明 : 假設 0k0 \sim k 答案非遞減, k+1k + 1 的最大位元最多比 kk 的最大位元大 11, 所以 k+1k + 1 沒法轉移到比 kk 可以轉移到的數小的數, 因此 k+1k + 1 的答案不會比 kk 小, 數學歸納法可證。

範例程式碼

C++ 範例
#include <bits/stdc++.h>
#define IO ios_base::sync_with_stdio(0), cin.tie(0)
#define int long long
using namespace std;

signed main() {
IO;
int n, ans = 0;
cin >> n;
while(n > 0) {
int big = -1;
for(int i = n; i > 0; i /= 10) {
big = max(big, i % 10);
}
n -= big;
ans++;
}
cout << ans;
}

想法 2 : DP

從測資我們可以知道 2727 可以從兩個地方轉移過來,分別是 2020 以及 2525,因此只要先求出 20202525 所需要的最小操作次數就可以推得 2727 所需要的最小操作次數。

作法

ii 等於 11 開始計算每個數字所需要的最小操作次數,就可以確保之後的數字一定有轉移點

狀態定義

dpidp_{i} 為將 ii 變成 00 所需要的最小操作次數

狀態轉移

對於每個位數的數字 CiC_i,轉移式為 dpi=min(dpi,dpiCi)dp_{i} = \min(dp_{i}, dp_{i - C_i})

範例程式碼

C++ 範例
#include <bits/stdc++.h>
#define IO ios_base::sync_with_stdio(0), cin.tie(0)
#define int long long
using namespace std;

signed main() {
IO;
int n;
cin >> n;
vector<int>dp(n + 1, INT_MAX);
dp[0] = 0;
for(int i = 1; i <= n; i++) {
for(int j = i; j > 0; j /= 10) {
dp[i] = min(dp[i], dp[i - (j % 10)] + 1);
}
}
cout << dp[n];
}